import os.path

import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from conf import conf
from tools.framework import get_ui_value, gen_result_folder_name
from tools.file_manager import gen_data_name
from core.constant import *
from module.static_module.parent.model import AdditionModule
from datetime import datetime as datetime_

matplotlib.use("Agg")

# 设置字体属性，确保中文正常显示
plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体为SimHei，这是一个支持中文的字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题


class SectorGuideModel(AdditionModule):
    def __init__(self, master):
        super().__init__(master, Module.SectorGuide)
        # 实体类映射视图类变量数据
        self.mk_data_file_ls = []  # 行情文件
        self.sector_file_ls = []  # 板块文件
        self.sector_name_ls = []  # 板块名称
        self.fighting_mode_ls = []  # 执行模式

        # 映射视图类变量数据默认值
        self.mk_data_file = []  # 行情文件
        self.sector_file = []  # 板块文件
        self.sector_name = ''  # 板块名称
        self.fighting_mode = []  # 执行模式

        # 实体类结构变量
        self.sub_view = None
        self.sector_data_df = None
        self.sector_data_df_dc: dict[str, pd.DataFrame] = {}

        self.draw_num = int((
                                    conf.AdditionModule.visualization_x_px.value - conf.AdditionModule.axis_y_px.value) // conf.AdditionModule.k_px.value)
        self.draw_data: pd.DataFrame = None

    def sec_init(self):
        # 实体类映射视图类变量数据
        self.mk_data_file_ls = []  # 行情文件
        self.sector_file_ls = []  # 板块文件
        self.sector_name_ls = []  # 板块名称
        self.fighting_mode_ls = ["板块收盘", "板块K线", "个股收盘", "组合K线"]  # 执行模式

        from module.addition_module.sector_guide.view import SectorGuideView
        self.sub_view = SectorGuideView(self)

    def get_ui_params(self):
        # 获取ui界面的相关参数
        values, indices = self.sub_view.auto_layout.get_value(
            LabelMember.MkDataFile)
        self.mk_data_file = get_ui_value(values, indices, WidgetCategory.Entry)
        values, indices = self.sub_view.auto_layout.get_value(
            LabelMember.SectorFile)
        self.sector_file = get_ui_value(values, indices, WidgetCategory.Entry)
        values, indices = self.sub_view.auto_layout.get_value(
            LabelMember.SectorName)
        self.sector_name = get_ui_value(values, indices, WidgetCategory.Entry)
        values, indices = self.sub_view.auto_layout.get_value(
            LabelMember.FightingMode)
        self.fighting_mode = get_ui_value(values, indices, WidgetCategory.Combobox)

    def on_ok(self):
        self.get_ui_params()
        # 获取基本信息
        if self.fighting_mode == "板块收盘":
            # 加载行情数据和板块文件
            mk_data_dc: dict[str, pd.DataFrame] = self.master.file_manager.read_dc_csv(self.mk_data_file)
            symbol_ls = list(mk_data_dc.keys())
            sector_data: pd.DataFrame = self.master.file_manager.read_csv(self.sector_file)
            if self.sector_name:
                sector_ls = self.sector_name.split(",")
            else:
                sector_ls = sector_data["category"].unique().tolist()
            # 遍历板块并生成信息表
            sector_mk_data_dc: dict[str, list[pd.DataFrame]] = {}
            for i, (index_o, row) in enumerate(sector_data.iterrows()):
                if row["category"] in sector_ls:
                    pass
                else:
                    continue
                if row["code"] in symbol_ls:
                    # 将该df新增rate列并计入信息
                    mk_data_dc[row["code"]]["close_100"] = mk_data_dc[row["code"]]["close"] / \
                                                           mk_data_dc[row["code"]]["close"].iloc[
                                                               0] * conf.AdditionModule.ori_value.value
                    category = row["category"]
                    if category in sector_mk_data_dc.keys():
                        sector_mk_data_dc[category].append(mk_data_dc[row["code"]])
                    else:
                        sector_mk_data_dc[category] = [mk_data_dc[row["code"]]]
                else:
                    pass
            # 计算板块内的close_100平均值
            self.sector_data_df: pd.DataFrame = pd.DataFrame([])
            self.sector_data_df.index.name = "datetime"
            for category_o, mk_data_ls_o in sector_mk_data_dc.items():
                # 将mk_data_ls_o下所有mk_data的close_x列的数据取平均组合新值
                ls_member_num = len(mk_data_ls_o)
                mk_data_col_o = None
                for mk_data_o in mk_data_ls_o:
                    if mk_data_col_o is None:
                        mk_data_col_o = mk_data_o["close_100"] / ls_member_num
                    else:
                        mk_data_col_o = mk_data_col_o + mk_data_o["close_100"] / ls_member_num
                mk_data_col_o.name = category_o
                self.sector_data_df[category_o] = mk_data_col_o.round(3)

            # 将整合后的板块数据存储
            sector_data_folder = os.path.join(self.master.file_manager.result_path, ResultFolder.ADD.value,
                                              gen_result_folder_name(ResultFolder.ADD))
            sector_data_name = gen_data_name(DataCategory.Sector)
            sector_data_path = os.path.join(sector_data_folder, sector_data_name + '.csv')
            self.master.file_manager.save_csv(self.sector_data_df, sector_data_path)
        elif self.fighting_mode == "板块K线":
            # 加载板块数据
            mk_data_dc: dict[str, pd.DataFrame] = self.master.file_manager.read_dc_csv(self.mk_data_file)
            symbol_ls = list(mk_data_dc.keys())
            sector_data: pd.DataFrame = self.master.file_manager.read_csv(self.sector_file)
            if self.sector_name:
                sector_ls = self.sector_name.split(",")
            else:
                sector_ls = sector_data["category"].unique().tolist()
            # 合并为一般行情数据，包括ohlcv数据
            # 遍历板块并生成信息表
            sector_mk_data_dc: dict[str, list[pd.DataFrame]] = {}
            for i, (index_o, row) in enumerate(sector_data.iterrows()):
                if row["category"] in sector_ls:
                    pass
                else:
                    continue
                if row["code"] in symbol_ls:
                    # 将该df新增rate列并计入信息
                    mk_data_dc[row["code"]]["open_100"] = mk_data_dc[row["code"]]["open"] / \
                                                          mk_data_dc[row["code"]]["close"].iloc[
                                                              0] * conf.AdditionModule.ori_value.value
                    mk_data_dc[row["code"]]["high_100"] = mk_data_dc[row["code"]]["high"] / \
                                                          mk_data_dc[row["code"]]["close"].iloc[
                                                              0] * conf.AdditionModule.ori_value.value
                    mk_data_dc[row["code"]]["low_100"] = mk_data_dc[row["code"]]["low"] / \
                                                         mk_data_dc[row["code"]]["close"].iloc[
                                                             0] * conf.AdditionModule.ori_value.value
                    mk_data_dc[row["code"]]["close_100"] = mk_data_dc[row["code"]]["close"] / \
                                                           mk_data_dc[row["code"]]["close"].iloc[
                                                               0] * conf.AdditionModule.ori_value.value
                    category = row["category"]
                    if category in sector_mk_data_dc.keys():
                        sector_mk_data_dc[category].append(mk_data_dc[row["code"]])
                    else:
                        sector_mk_data_dc[category] = [mk_data_dc[row["code"]]]
                else:
                    pass

            # 计算板块内的close_100平均值
            for category_o, mk_data_ls_o in sector_mk_data_dc.items():
                self.sector_data_df: pd.DataFrame = pd.DataFrame([])
                self.sector_data_df.index.name = "datetime"
                # 将mk_data_ls_o下所有mk_data的close_x列的数据取平均组合新值
                ls_member_num = len(mk_data_ls_o)
                open_sr: pd.Series = None
                high_sr: pd.Series = None
                low_sr: pd.Series = None
                close_sr: pd.Series = None
                volume_sr: pd.Series = None
                for mk_data_o in mk_data_ls_o:
                    if open_sr is None:
                        open_sr = mk_data_o["open_100"] / ls_member_num
                        high_sr = mk_data_o["high_100"] / ls_member_num
                        low_sr = mk_data_o["low_100"] / ls_member_num
                        close_sr = mk_data_o["close_100"] / ls_member_num
                        volume_sr = mk_data_o["volume"]
                    else:
                        open_sr = open_sr + mk_data_o["open_100"] / ls_member_num
                        high_sr = high_sr + mk_data_o["high_100"] / ls_member_num
                        low_sr = low_sr + mk_data_o["low_100"] / ls_member_num
                        close_sr = close_sr + mk_data_o["close_100"] / ls_member_num
                        volume_sr = volume_sr + mk_data_o["volume"]

                self.sector_data_df["open"] = open_sr.round(3)
                self.sector_data_df["high"] = high_sr.round(3)
                self.sector_data_df["low"] = low_sr.round(3)
                self.sector_data_df["close"] = close_sr.round(3)
                self.sector_data_df["volume"] = volume_sr.round(3)

                self.sector_data_df_dc[category_o] = self.sector_data_df

            # 将整合后的板块数据存储
            sector_data_name = gen_data_name(DataCategory.Mk)
            sector_data_path = os.path.join(self.master.file_manager.market_data_path, sector_data_name + '.csv')
            self.master.file_manager.save_dc_csv(self.sector_data_df_dc, sector_data_path)
        elif self.fighting_mode == "个股收盘":
            # 加载板块数据
            mk_data_dc: dict[str, pd.DataFrame] = self.master.file_manager.read_dc_csv(self.mk_data_file)
            # 获取有效的symbol。
            if self.sector_file:
                sector_data: pd.DataFrame = self.master.file_manager.read_csv(self.sector_file)
                if self.sector_name:
                    sector_ls = self.sector_name.split(",")
                else:
                    sector_ls = sector_data["category"].unique().tolist()
                all_symbol_ls = []
                for sector_o in sector_ls:
                    filtered_data = sector_data[sector_data['category'] == sector_o]
                    all_symbol_ls += filtered_data['code'].tolist()
                symbol_ls = []
                for symbol_o in list(mk_data_dc.keys()):
                    if symbol_o in all_symbol_ls:
                        symbol_ls.append(symbol_o)
            else:
                symbol_ls = list(mk_data_dc.keys())

            if len(symbol_ls) == 0:
                raise ValueError("获取的标的列表为空，逻辑错误。")

            stock_close_df: pd.DataFrame = pd.DataFrame([], columns=symbol_ls)
            stock_close_df.index.name = "datetime"
            for stock_o in symbol_ls:
                stock_sr = mk_data_dc[stock_o]["close"]
                stock_close_df[stock_o] = stock_sr
            # 将整合后的板块数据存储
            stock_close_folder = os.path.join(self.master.file_manager.result_path, ResultFolder.ADD.value,
                                              gen_result_folder_name(ResultFolder.ADD))
            stock_close_name = gen_data_name(DataCategory.Sector)
            stock_close_path = os.path.join(stock_close_folder, stock_close_name + '.csv')
            self.master.file_manager.save_csv(stock_close_df, stock_close_path)
        elif self.fighting_mode == "组合K线":
            # 组合名称
            portfolio_name = "股票组合" + datetime_.now().strftime("%m%d")
            # 股票代码列表
            if self.sector_name:
                stock_ls = self.sector_name.split(",")
            else:
                raise ValueError("股票组合代码为空，逻辑错误。")
            # 加载板块数据

            mk_data_dc: dict[str, pd.DataFrame] = self.master.file_manager.read_dc_csv(self.mk_data_file)
            symbol_ls = list(mk_data_dc.keys())
            sector_data: pd.DataFrame = self.master.file_manager.read_csv(self.sector_file)

            # 合并为一般行情数据，包括ohlcv数据
            # 遍历板块并生成信息表
            sector_mk_data_dc: dict[str, list[pd.DataFrame]] = {}
            for stock_o in stock_ls:
                # 将该df新增rate列并计入信息
                mk_data_dc[stock_o]["open_100"] = mk_data_dc[stock_o]["open"] / \
                                                  mk_data_dc[stock_o]["close"].iloc[
                                                      0] * conf.AdditionModule.ori_value.value
                mk_data_dc[stock_o]["high_100"] = mk_data_dc[stock_o]["high"] / \
                                                  mk_data_dc[stock_o]["close"].iloc[
                                                      0] * conf.AdditionModule.ori_value.value
                mk_data_dc[stock_o]["low_100"] = mk_data_dc[stock_o]["low"] / \
                                                 mk_data_dc[stock_o]["close"].iloc[
                                                     0] * conf.AdditionModule.ori_value.value
                mk_data_dc[stock_o]["close_100"] = mk_data_dc[stock_o]["close"] / \
                                                   mk_data_dc[stock_o]["close"].iloc[
                                                       0] * conf.AdditionModule.ori_value.value
                portfolio_name = portfolio_name  # 此为股票组合%m%d板块
                if portfolio_name in sector_mk_data_dc.keys() and stock_o != conf.AdditionModule.index_code.value:
                    sector_mk_data_dc[portfolio_name].append(mk_data_dc[stock_o])
                elif portfolio_name in sector_mk_data_dc.keys() and stock_o == conf.AdditionModule.index_code.value:
                    pass
                else:
                    sector_mk_data_dc[portfolio_name] = [mk_data_dc[stock_o]]
                # 将个股数据也加入进去
                code_sector = stock_o + ' ' + sector_data[sector_data["code"] == stock_o]["name"].tolist()[0] + "-" + sector_data[sector_data["code"] == stock_o]["category"].tolist()[0]
                sector_mk_data_dc[code_sector] = [mk_data_dc[stock_o]]

            # 计算板块内的close_100平均值
            for category_o, mk_data_ls_o in sector_mk_data_dc.items():
                self.sector_data_df: pd.DataFrame = pd.DataFrame([])
                self.sector_data_df.index.name = "datetime"
                # 将mk_data_ls_o下所有mk_data的close_x列的数据取平均组合新值
                ls_member_num = len(mk_data_ls_o)
                open_sr: pd.Series = None
                high_sr: pd.Series = None
                low_sr: pd.Series = None
                close_sr: pd.Series = None
                volume_sr: pd.Series = None
                for mk_data_o in mk_data_ls_o:
                    if open_sr is None:
                        open_sr = mk_data_o["open_100"] / ls_member_num
                        high_sr = mk_data_o["high_100"] / ls_member_num
                        low_sr = mk_data_o["low_100"] / ls_member_num
                        close_sr = mk_data_o["close_100"] / ls_member_num
                        volume_sr = mk_data_o["volume"]
                    else:
                        open_sr = open_sr + mk_data_o["open_100"] / ls_member_num
                        high_sr = high_sr + mk_data_o["high_100"] / ls_member_num
                        low_sr = low_sr + mk_data_o["low_100"] / ls_member_num
                        close_sr = close_sr + mk_data_o["close_100"] / ls_member_num
                        volume_sr = volume_sr + mk_data_o["volume"]

                self.sector_data_df["open"] = open_sr.round(3)
                self.sector_data_df["high"] = high_sr.round(3)
                self.sector_data_df["low"] = low_sr.round(3)
                self.sector_data_df["close"] = close_sr.round(3)
                self.sector_data_df["volume"] = volume_sr.round(3)

                # 满足个性化需求，计算各个category_o对应的收益率（近一年） | 风险率（近一年） | 最大回撤
                # 并打印
                # 总收益率
                total_return = self.sector_data_df["close"].iloc[-1] / self.sector_data_df["close"].iloc[0] - 1

                # 风险率
                volatility = np.std(self.sector_data_df["close"]) / self.sector_data_df["close"].iloc[-1]

                # 最大回撤
                rolling_max = self.sector_data_df["close"].cummax()
                daily_drawdown = self.sector_data_df["close"] / rolling_max - 1
                max_drawdown = -daily_drawdown.min()

                yield_rate = str(round(total_return * 100, 2)) + '%'
                risk_rate = str(round(volatility * 100, 2)) + '%'
                max_withdrawal = str(round(max_drawdown * 100, 2)) + '%'
                print(f"{category_o}的收益率：{yield_rate} | 风险率：{risk_rate} | 最大回撤：{max_withdrawal}")
                # 进一步输出股票/组合的平均12个点的数值（近一年）
                num_values = 12
                # 计算间隔
                total_length = len(self.sector_data_df["close"])
                step = total_length // (num_values - 1)  # -1是因为我们要在间隔之间选择点

                # 使用步长生成索引
                indices = np.arange(0, total_length, step)

                # 确保索引不超过Series的长度
                indices = np.clip(indices, 0, total_length - 1).astype(int)

                # 选择这些索引对应的值
                selected_values = self.sector_data_df["close"].iloc[indices]

                # 返回值的列表形式
                value_12_ls = selected_values.tolist()
                print(f"{category_o}的近12序列：{value_12_ls}")
                self.sector_data_df_dc[category_o] = self.sector_data_df

            # 将整合后的板块数据存储
            sector_data_name = gen_data_name(DataCategory.Mk)
            sector_data_path = os.path.join(self.master.file_manager.market_data_path, sector_data_name + '.csv')
            self.master.file_manager.save_dc_csv(self.sector_data_df_dc, sector_data_path)
        else:
            raise ValueError("未收录的模式，逻辑错误。")

        pass

    def on_draw(self):
        self.get_ui_params()
        # 划分情况，若为K线数据加载dc数据并处理为收盘价数据
        if DataCategory.Mk.value in self.mk_data_file:
            sector_data_dc = self.master.file_manager.read_dc_csv(self.mk_data_file)
            # 提取各板块的收盘价进行整合
            portfolio_ls = list(sector_data_dc.keys())
            sector_data: pd.DataFrame = pd.DataFrame([])
            for portfolio_o in portfolio_ls:
                portfolio_data_sr = sector_data_dc[portfolio_o]["close"]
                sector_data[portfolio_o] = portfolio_data_sr
        # 若为收盘价数据则直接读取
        else:
            # 加载板块数据
            sector_data = self.master.file_manager.read_csv(self.mk_data_file)
        # 筛选部分样本数据进行绘制
        # indices = np.linspace(0, len(sector_data) - 1, self.draw_num).astype(int)
        indices = np.linspace(0, len(sector_data) - 1, self.draw_num, endpoint=True, dtype=int)
        equity_data_sampled = sector_data.iloc[indices]
        # 选择要绘制的行情数据
        self.draw_data = equity_data_sampled
        # 调整板块的先后顺序
        # new_order = ["指数", "元件", "电力", "银行", "电池", "白酒", "光伏设备"][::-1]
        # self.draw_data = self.draw_data[new_order]
        last_row = self.draw_data.iloc[-1]
        sorted_indexes = last_row.sort_values().index.tolist()
        if conf.AdditionModule.index_sector.value in sorted_indexes:
            new_order = [conf.AdditionModule.index_sector.value]
        else:
            new_order = []
        except_ls = conf.AdditionModule.except_ls.value
        for index_o in sorted_indexes:
            if index_o not in except_ls:
                new_order.append(index_o)
        self.draw_data = self.draw_data[new_order]
        # 执行视图模块相关函数
        self.sub_view.draw_dynamic_graph()

        pass
